// Copyright © yanghy. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and limitations under the License.

package vtedit

import (
	"bytes"
	"fmt"
	"github.com/energye/designer/consts"
	"github.com/energye/designer/pkg/dast"
	"github.com/energye/designer/pkg/logs"
	"github.com/energye/designer/pkg/tool"
	"github.com/energye/lcl/lcl"
	"github.com/energye/lcl/types"
	"strconv"
)

// 查看器的数据类型

// 节点数据
type TEditLinkNodeData struct {
	Metadata      *lcl.ComponentProperties // 组件属性元数据
	Name          string                   // 属性名
	Index         int32                    // 值索引 值是数组类型时，选中的索引
	Checked       bool                     // 选中列表 值是数组类型时，是否选中
	StringValue   string                   // 属性值 string
	FloatValue    float64                  // 属性值 float64
	BoolValue     bool                     // 属性值 bool
	IntValue      int                      // 属性值 int
	EventState    consts.TEventState       // 属性事件更新 状态
	Class         TPropClass               // 属性值 class 实例
	CheckBoxValue []*TEditLinkNodeData     // 属性值 checkbox
	ComboBoxValue []*TEditLinkNodeData     // 属性值 combobox
	Type          consts.PropertyDataType  // 属性值类型
}

// 属性值 class
type TPropClass struct {
	Instance uintptr // 属性值 class 实例
	Count    int32   // 属性值 class 属性数量
}

// 编辑数据返回字符串值
func (m *TEditLinkNodeData) EditStringValue() string {
	switch m.Type {
	case consts.PdtText, consts.PdtUint16:
		return m.StringValue
	case consts.PdtInt, consts.PdtInt64:
		return strconv.Itoa(m.IntValue)
	case consts.PdtFloat:
		val := strconv.FormatFloat(m.FloatValue, 'f', 2, 64)
		return val
	case consts.PdtCheckBox:
		return strconv.FormatBool(m.Checked)
	case consts.PdtCheckBoxList:
		return m.StringValue
	case consts.PdtComboBox:
		return m.StringValue
	case consts.PdtColorSelect:
		return fmt.Sprintf("0x%X", m.IntValue)
	case consts.PdtClass:
		return m.StringValue
	case consts.PdtMethod:
		//value := ""
		//if m.Index != -1 && m.Index < int32(len(m.ComboBoxValue)) {
		//	value = m.ComboBoxValue[m.Index].StringValue
		//}
		//return value
		return m.StringValue
	default:
		return ""
	}
}

// 编辑数据返回原始类型值
func (m *TEditLinkNodeData) EditValue() any {
	switch m.Type {
	case consts.PdtText, consts.PdtUint16:
		return m.StringValue
	case consts.PdtInt, consts.PdtInt64:
		return m.IntValue
	case consts.PdtFloat:
		return m.FloatValue
	case consts.PdtCheckBox:
		return m.Checked
	case consts.PdtCheckBoxList:
		return m.StringValue
	case consts.PdtComboBox:
		return m.StringValue
	case consts.PdtColorSelect:
		return m.IntValue
	case consts.PdtClass:
		return m.StringValue
	case consts.PdtMethod:
		//var value any
		//if m.Index != -1 && m.Index < int32(len(m.ComboBoxValue)) {
		//	value = m.ComboBoxValue[m.Index].StringValue
		//}
		//return value
		return m.StringValue
	default:
		return ""
	}
}

func (m *TEditLinkNodeData) SetEditValue(value any) {
	switch m.Type {
	case consts.PdtText, consts.PdtUint16:
		m.StringValue = value.(string)
	case consts.PdtInt, consts.PdtInt64:
		m.IntValue, _ = tool.StrToInt(tool.IntToString(value))
	case consts.PdtFloat:
		m.FloatValue = value.(float64)
	case consts.PdtCheckBox:
		m.Checked = value.(bool)
	case consts.PdtCheckBoxList:
		m.StringValue = value.(string)
	case consts.PdtComboBox:
		m.StringValue = value.(string)
	case consts.PdtColorSelect:
		m.IntValue, _ = tool.StrToInt(tool.IntToString(value))
	case consts.PdtMethod:
		m.StringValue = value.(string)
		if m.ComboBoxValue == nil && m.StringValue != "" {
			// 事实上: 此处只在初始化时设置临时默认值. 或被设置新值时做为一个临时数据
			// 主要用于未被修改时可保证数据完整性
			// 当被编辑后会被覆盖
			m.ComboBoxValue = []*TEditLinkNodeData{
				{StringValue: defaultText},
				{StringValue: m.StringValue},
			}
			m.Index = 1 // 设置值为 1 表示被修改
		}
	}
}

func (m *TEditLinkNodeData) Clone() *TEditLinkNodeData {
	if m == nil {
		return nil
	}
	clone := &TEditLinkNodeData{
		Name:        m.Name,
		Index:       m.Index,
		Checked:     m.Checked,
		StringValue: m.StringValue,
		FloatValue:  m.FloatValue,
		BoolValue:   m.BoolValue,
		IntValue:    m.IntValue,
		Type:        m.Type,
		Class:       TPropClass{Instance: m.Class.Instance, Count: m.Class.Count},
	}
	if m.Metadata != nil {
		cloneMetadata := *m.Metadata
		clone.Metadata = &cloneMetadata
	}

	// 深拷贝CheckBoxValue切片（递归克隆每个元素）
	if m.CheckBoxValue != nil {
		clone.CheckBoxValue = make([]*TEditLinkNodeData, len(m.CheckBoxValue))
		for i, item := range m.CheckBoxValue {
			clone.CheckBoxValue[i] = item.Clone()
		}
	}

	// 深拷贝ComboBoxValue切片（递归克隆每个元素）
	if m.ComboBoxValue != nil {
		clone.ComboBoxValue = make([]*TEditLinkNodeData, len(m.ComboBoxValue))
		for i, item := range m.ComboBoxValue {
			clone.ComboBoxValue[i] = item.Clone()
		}
	}
	return clone
}

// 设计组件接口
type IDesigningComponent interface {
	UpdateComponentPropertyToObject(nodeData *TEditNodeData)
	UpdateComponentBindEventToCode(updateNodeData *TEditNodeData)
	GetRecvMethods() []*dast.TFuncInfo
	GetClassName() string
	GetName() string
	GetMod() string
}

// 编辑的节点数据
type TEditNodeData struct {
	Parent              *TEditNodeData      // 父属性节点
	Child               []*TEditNodeData    // 子属性节点
	EditNodeData        *TEditLinkNodeData  // 编辑数据
	OriginNodeData      *TEditLinkNodeData  // 原始数据
	AffiliatedNode      types.PVirtualNode  // 所属属性树节点
	AffiliatedComponent IDesigningComponent // 所属组件对象
}

var (
	// 组件属性数据列表, key: 节点指针 value: 节点数据
	propertyTreeDataList = make(map[types.PVirtualNode]*TEditNodeData)
)

// 创建一个编辑节点数据
func NewEditLinkNodeData(prop *lcl.ComponentProperties) *TEditLinkNodeData {
	m := &TEditLinkNodeData{Metadata: prop}
	// 构建当前节点数据
	m.Build()
	return m
}

// 添加数据到指定节点
func AddPropertyNodeData(tree lcl.ILazVirtualStringTree, parent types.PVirtualNode, data *TEditNodeData) types.PVirtualNode {
	node := tree.AddChild(parent, 0)
	// 节点设置到节点数据
	data.AffiliatedNode = node
	// 设置到数据列表, 增加绑定关系
	propertyTreeDataList[node] = data
	if data.Type() == consts.PdtCheckBoxList {
		// 复选框列表
		dataList := data.EditNodeData.CheckBoxValue
		buf := bytes.Buffer{}
		buf.WriteString("[")
		i := 0
		for _, item := range dataList {
			if item.Checked {
				if i > 0 {
					buf.WriteString(",")
				}
				buf.WriteString(item.Name)
				i++
			}
			newItemData := &TEditNodeData{EditNodeData: item, OriginNodeData: item.Clone(), AffiliatedComponent: data.AffiliatedComponent}
			AddPropertyNodeData(tree, node, newItemData)
		}
		buf.WriteString("]")
		data.EditNodeData.StringValue = buf.String()
	} else if data.Type() == consts.PdtClass {
		for _, nodeData := range data.Child {
			AddPropertyNodeData(tree, node, nodeData)
		}
	}
	return node
}

// 获取节点属性数据
func GetPropertyNodeData(node types.PVirtualNode) *TEditNodeData {
	if data, ok := propertyTreeDataList[node]; ok {
		return data
	}
	return nil
}

// 删除节点属性数据
func DelPropertyNodeData(node types.PVirtualNode) {
	delete(propertyTreeDataList, node)
}

func (m *TEditNodeData) Free() {
	m.Parent = nil
	m.EditNodeData = nil
	m.OriginNodeData = nil
	m.AffiliatedComponent = nil
	DelPropertyNodeData(m.AffiliatedNode)
	for _, child := range m.Child {
		child.Free()
	}
}

func (m *TEditNodeData) Type() consts.PropertyDataType {
	return m.EditNodeData.Type
}
func (m *TEditNodeData) Class() TPropClass {
	return m.EditNodeData.Class
}
func (m *TEditNodeData) Name() string {
	return m.EditNodeData.Name
}

// 从设计属性更新到组件属性
func (m *TEditNodeData) FormInspectorPropertyToComponentProperty() {
	if m.EditNodeData != nil {
		logs.Debug("TEditLinkNodeData FormInspectorPropertyToComponentProperty property-name:", m.EditNodeData.Name)
		m.AffiliatedComponent.UpdateComponentPropertyToObject(m)
	}
}

func (m *TEditNodeData) FormInspectorEventToComponentEvent() {
	if m.EditNodeData != nil {
		logs.Debug("TEditLinkNodeData FormInspectorEventToComponentEvent property-name:", m.EditNodeData.Name)
		m.AffiliatedComponent.UpdateComponentBindEventToCode(m)
	}
}

// 从组件属性更新到设计属性
func (m *TEditNodeData) FormComponentPropertyToInspectorProperty() {
	if m.EditNodeData != nil {
		logs.Debug("TEditLinkNodeData FormComponentPropertyToInspectorProperty property-name:", m.EditNodeData.Name)
	}

	//m.AffiliatedNode
}

// 是否被修改
func (m *TEditNodeData) IsModify() bool {
	switch m.Type() {
	case consts.PdtCheckBox:
		return m.EditNodeData.Checked != m.OriginNodeData.Checked
	case consts.PdtText, consts.PdtUint16:
		return m.EditNodeData.StringValue != m.OriginNodeData.StringValue
	case consts.PdtInt, consts.PdtInt64:
		return m.EditNodeData.IntValue != m.OriginNodeData.IntValue
	case consts.PdtFloat:
		return m.EditNodeData.FloatValue != m.OriginNodeData.FloatValue
	case consts.PdtCheckBoxList:
		// CheckBox 判断集合是否修改
		for i, item := range m.EditNodeData.CheckBoxValue {
			if item.Checked != m.OriginNodeData.CheckBoxValue[i].Checked {
				return true
			}
		}
	case consts.PdtComboBox:
		return m.EditNodeData.StringValue != m.OriginNodeData.StringValue
	case consts.PdtColorSelect:
		return m.EditNodeData.IntValue != m.OriginNodeData.IntValue
	case consts.PdtClass:
		// 类实例, 需要判断类下的属性是否被修改
		for _, child := range m.Child {
			if child.IsModify() {
				return true
			}
		}
	case consts.PdtMethod:
		return m.EditNodeData.Index > 0 // 索引大于0表示修改
	}
	return false
}

// 获取修改class的子节点
func (m *TEditNodeData) GetModifyClassChildNodeData() *TEditNodeData {
	if m.Type() == consts.PdtClass {
		for _, child := range m.Child {
			if child.IsModify() {
				if child.Type() == consts.PdtClass {
					return child.GetModifyClassChildNodeData()
				} else {
					return child
				}
			}
		}
	}
	return nil
}

// 编辑数据返回字符串值
func (m *TEditNodeData) EditStringValue() string {
	return m.EditNodeData.EditStringValue()
}

// 编辑数据返回原始类型值
func (m *TEditNodeData) EditValue() any {
	return m.EditNodeData.EditValue()
}

// 返回编辑字符串值
func (m *TEditNodeData) SetEditValue(value any) {
	m.EditNodeData.SetEditValue(value)
}

// 获得类的路径 Txxx.Txxx.Txxx ...
func (m *TEditNodeData) Paths() []string {
	// todo 1: 可能存在的问题, 某父对象不是class一定是错误的
	var paths []string
	pData := m.Parent
	for pData != nil {
		if pData.Type() == consts.PdtClass { // todo 1
			paths = append(paths, pData.Name())
		} else {
			// 不正确, 直接退出
			panic("递归遍历属性节点对象路径错误, 对象非class类型, 节点必须为class类型: " + pData.Name())
		}
		pData = pData.Parent
	}
	return paths
}
